﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace oreimou
{
    class FileContent
    {
        FileStream f;
        public bool ForWrite { get { return f.CanWrite; } }
        public long Length { get { return f.Length; } }
        string FileInfo;
        public delegate void CpAlgo(Stream Input,Stream Output);
        public FileContent(string path,FileAccess fa)
        {
            FileMode fm;
            if (fa == FileAccess.Write) fm = FileMode.Create;
            else fm = FileMode.Open;
            f = File.Open(path,fm, fa);
            FileInfo =Path.Combine(Path.GetDirectoryName(path),"info.txt");
            FileStream fi = File.Open(FileInfo, FileMode.Create);
            fi.Close();
        }
        ~FileContent()
        {
            f.Close();
        }
        public void Seek(long offset)
        {
            f.Seek(offset, SeekOrigin.Begin);
        }
        public void SeekEnd()
        {
            f.Seek(0, SeekOrigin.End);
        }
        public long Postion { get { return f.Position; } }

        public byte[] FileHead(long offset=0)
        //读取文件头
        {
            byte[] buf = new byte[16];
            f.Seek(offset, SeekOrigin.Begin);
            f.Read(buf, 0, 16);
            return buf;

        }

        public long ReadInteger(int len)
        //读取整型
        {
            long ret = 0;
            if (len > 8) throw new TooLargeIntegerLengthExpection();
            byte[] buf = new byte[8];
            f.Read(buf, 0, len);
            for (int i = len - 1; i >= 0; i--)
            {
                ret <<= 8;
                ret += buf[i];
            }
            return ret;
        }

        public string ReadString(int len, Encoding en)
        //读取字符串
        {
            char[] ret;
            byte[] buf = new byte[1024];
            f.Read(buf, 0, len);
            ret = en.GetChars(buf, 0, len);
            return new String(ret);
        }

        public void Write(int len)        //写相关函数
        {
            f.Write(BitConverter.GetBytes(len), 0, 4);
        }
        public void Write(long len)
        {
            f.Write(BitConverter.GetBytes(len), 0, 8);
        }
        public void Write(short len)
        {
            f.Write(BitConverter.GetBytes(len), 0, 2);
        }
        public void Write(string str)
        {
            byte[] buf=Encoding.ASCII.GetBytes(str);
            f.Write(buf, 0, buf.Length);
        }

        public void Output(long offset, long size, string path, string name)//输出指定区间
        {
            StreamWriter sw = new StreamWriter(FileInfo, true);
            int block = 0x800;
            name = Path.Combine(path, name);

            FileStream fs = File.Open(name, FileMode.Create, FileAccess.Write);
            this.Seek(offset);
            byte[] buf = new byte[block];
            for (int i = 0; i <= size - block; i += block)
            {
                f.Read(buf, 0, block);
                fs.Write(buf, 0, block);
            }
            f.Read(buf, 0, (int)(size % block));
            fs.Write(buf, 0, (int)(size % block));
            
            sw.WriteLine(String.Format("{0} {1} {2}", Path.GetFileName(name), offset, size));
            Console.WriteLine(name);
            fs.Flush();
            fs.Close();
            sw.Close();
        }

        public void OutputCompress(long offset, long size, string path, string name, CpAlgo algo)//由压缩算法输出
        {
            StreamWriter sw = new StreamWriter(FileInfo, true);
            name = Path.Combine(path, name);

            FileStream fs = File.Open(name, FileMode.Create, FileAccess.Write);
            this.Seek(offset);
            byte[] cbuf = new byte[size];
            f.Read(cbuf, 0, (int)size);
            while (f.ReadByte() == 0) ;
            sw.WriteLine(String.Format("{0} {1:X} {2:X} {3:X} gz", Path.GetFileName(name), offset, size, f.Position - offset - 1));
            MemoryStream ms=new MemoryStream(cbuf);
            algo(ms, fs);
            Console.WriteLine(name + " compressed");
            sw.Close();
            fs.Flush();
            fs.Close();
        }

        internal void OutputFolder(string path, string name, int offset, int size, int cnt)
        {
            StreamWriter sw = new StreamWriter(FileInfo, true);
            name = Path.Combine(path, name);
            sw.WriteLine(String.Format("{0} {1} {2} 0 {3}", name, offset, size, cnt));
            if (!Directory.Exists(name))
                Directory.CreateDirectory(name);
            sw.Close();
        }
        internal string[] GetFolders(string name)
        {
            if (!Directory.Exists(name))
                throw new DirectoryNotFoundException(name);
            string[] dirs = Directory.GetDirectories(name);
            return dirs;
        }
        internal string[] GetFiles(string name)
        {
            if (!Directory.Exists(name))
                throw new DirectoryNotFoundException(name);
            string[] files = Directory.GetFiles(name);
            return files;
        }

        public int CreatHead(int size)
        {
            size -= 1;
            size /= 0x800;
            size += 1;
            size *= 0x800;
            f.Seek(0, SeekOrigin.End);
            byte[] hbuf = new byte[size];
            char[] Idstr={'G','P','D','A'};
            Encoding.ASCII.GetBytes(Idstr, 0, 4, hbuf, 0);
            f.Write(hbuf, 0, size);
            return size;
        }
        public int Input(FileInfo fi)
        {
            int count = 0;
            int amount=0;
            byte[] buf = new byte[0x800];
            f.Seek(0,SeekOrigin.End);
            FileStream fs = File.Open(fi.FullName, FileMode.Open, FileAccess.Read);

            amount=fs.Read(buf, 0, 0x800);
            while (amount == 0x800)
            {
                f.Write(buf, 0, 0x800);
                Array.Clear(buf, 0, 0x800);
                count++;
                amount = fs.Read(buf, 0, 0x800);
            }
            if (amount > 0)
            {
                f.Write(buf, 0, 0x800);
                count++;
            }

            Console.WriteLine(fi.FullName);
            return count * 0x800;
        }
        public void ChangeDir(string name)
        {
            Directory.SetCurrentDirectory(name);
        }
    }

}
